package com.huitone.smspfm.interfacz.core.filewriter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;

import com.bin.common.utils.FileUtils;
import com.bin.common.utils.StringUtils;
import com.huitone.smspfm.interfacz.logger.ExtLogger;


/**
 *  读写文件实现类
 * @author ozh
 *
 */
public class FileWriterClient implements WriterInterface{
	
	private static final ExtLogger logger = ExtLogger.create(FileWriterClient.class);
	
	private static final String defaultCharacter = "UTF-8";
	
	/**
	 * 文件可写状态
	 */
	protected boolean writerFlag = true;

	/**
	 * 文件路径
	 */
	protected String filePath = null;
	
	/**
	 * 文件名
	 */
	protected String fileName = null;
	
	/**
	 * 当前操作文件
	 */
	protected String currentFile = null;
	
	/**
	 * 文件名处理器
	 */
	protected CuttingFileConfig nameConfig = null;
	
	/**
	 * 定时切割
	 */
	protected FileWatchDog watchDog = null;
	
	/**
	 * 写入流
	 */
	protected BufferedWriter bufferedWriter = null;
	
	/**
	 * 读取流
	 */
	protected BufferedReader bufferedReader = null;
	
	/**
	 * 文件开始标识
	 */
	protected String wrapLeft = null;
	
	/**
	 * 文件结束标识
	 */
	protected String wrapRight = null;
	
	/**
	 * 行数达到该值时将切割文件
	 */
	protected long lineToCut = 1000;
	
	/**
	 * 当前在写的文件行数
	 */
	protected long lineCount = 0;
	
	/**
	 * 文件在指定时间间隔内,即便没有达到最大行值也必须必须切割
	 */
	protected long intvToCut = 30000;
	
	/**
	 * 最近一次切割文件的时间
	 */
	protected Date lastCutTime = new Date();
	
	protected Object objLock = new Object();
	
	
	
	public long getLineToCut() {
		return lineToCut;
	}

	public void setLineToCut(long lineToCut) {
		this.lineToCut = lineToCut;
	}

	public long getIntvToCut() {
		return intvToCut;
	}

	public void setIntvToCut(long intvToCut) {
		this.intvToCut = intvToCut;
	}

	public boolean isWriterFlag() {
		return writerFlag;
	}

	public void setWriterFlag(boolean isWriter) {
		this.writerFlag = isWriter;
	}

	public String getCurrentFile() {
		return currentFile;
	}

	public void setCurrentFile(String currentFile) {
		this.currentFile = currentFile;
	}

	public BufferedWriter getBufferedWriter() {
		return bufferedWriter;
	}

	public void setBufferedWriter(BufferedWriter bufferedWriter) {
		this.bufferedWriter = bufferedWriter;
	}

	public BufferedReader getBufferedReader() {
		return bufferedReader;
	}

	public void setBufferedReader(BufferedReader bufferedReader) {
		this.bufferedReader = bufferedReader;
	}

	public String getWrapLeft() {
		return wrapLeft;
	}

	public void setWrapLeft(String wrapLeft) {
		this.wrapLeft = wrapLeft;
	}

	public String getWrapRight() {
		return wrapRight;
	}

	public void setWrapRight(String wrapRight) {
		this.wrapRight = wrapRight;
	}

	protected FileWriterClient() {	}
	
	public  static FileWriterClient getFileWriterClient(String filePath,String fileName,CuttingFileConfig nameConfig) {	
		if( ! StringUtils.isEmpty(filePath) && ! StringUtils.isEmpty(fileName) && nameConfig != null){
			FileWriterClient client = new FileWriterClient();
			client.filePath = filePath;
			client.fileName = fileName;
			client.nameConfig = nameConfig;
			client.init();
			
			return client;
		} else {
			return null;
		}
	}
	
	protected void init() {	
		this.currentFile = this.filePath + File.separator + this.fileName;
		
		try {
			bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(FileUtils.createFile(this.currentFile)), defaultCharacter));
			lineCount = bufferedReader.lines().count();
			bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.currentFile,true), defaultCharacter));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
	public void enableWatchDog() {

		if (watchDog == null || !watchDog.isAlive()) {

			watchDog = new FileWatchDog();
			watchDog.setDs(new DoSome() {

				@Override
				public void doSome() {

					File filz = new File(currentFile);
					long lastModified = filz.lastModified();
					long currentTimeMillis = System.currentTimeMillis();

					if (lastModified != 0
							&& lineCount != 0
							&& (( currentTimeMillis - lastCutTime.getTime()) >= intvToCut)) {
						try {
							cut();
						} catch (IOException e) {
							logger.error("文件切割的时候发生错误", e);
						}
					}
				}
			});
			watchDog.start();
		}
	}
	
	public synchronized void writeLine(String string) throws IOException {

		if (!StringUtils.isEmpty(string)) {

			if (lineCount == 0) {
				if (!StringUtils.isEmpty(wrapLeft)) {
					bufferedWriter.write(wrapLeft);
					bufferedWriter.newLine();
				}
			}

			bufferedWriter.write(string);
			bufferedWriter.newLine();
			bufferedWriter.flush();

			lineCount++;

			if (lineCount >= lineToCut) {
				cut();
			}
		}
	}
	
	public synchronized void cut() throws IOException {
		synchronized (objLock) {
			
		
		this.writerFlag = false;
		if (!StringUtils.isEmpty(wrapRight)) {
			bufferedWriter.write(wrapRight);
			bufferedWriter.newLine();
		}
		bufferedReader.close();
		bufferedWriter.flush();
		bufferedWriter.close();

		File filz = new File(this.currentFile);
		FileUtils.rename(filz, nameConfig.creaeName());
		if (!filz.exists()) {
			filz = FileUtils.createFile(this.currentFile);
		}
		this.init();
		lastCutTime = new Date();
		this.writerFlag = true;
		}
	}

	@Override
	public void write(String msg) throws IOException {
		this.writeLine(msg);
	}

	interface DoSome {
		void doSome();
	}

	class FileWatchDog extends Thread {

		private DoSome ds = null;

		private boolean keepGoing = true;

		public DoSome getDs() {
			return ds;
		}

		public void setDs(DoSome ds) {
			this.ds = ds;
		}

		@Override
		public void run() {

			while (!this.isInterrupted() && isKeepGoing()) {

				ds.doSome();

				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
				}
			}
		}

		public boolean isKeepGoing() {
			return keepGoing;
		}

		public void setKeepGoing(boolean keepGoing) {
			this.keepGoing = keepGoing;
		}
	}

	@Override
	public void destroy() {
		try {
			this.flush();
		} catch (IOException e) {
			logger.error("runing flush() error ! message: " + e.getMessage());
		}
		if(watchDog != null){
			watchDog.setKeepGoing(false);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {}
			watchDog = null;
		}
			
		
	}

	@Override
	public void flush() throws IOException {
		if(bufferedReader != null){
			bufferedReader.close();
		}
		
		if(bufferedWriter != null){
			bufferedWriter.close();
		}
		
	}

	@Override
	public boolean isWriter() {
		
		return isWriterFlag();
	}

}
